home *** CD-ROM | disk | FTP | other *** search
/ NetNews Offline 2 / NetNews Offline Volume 2.iso / news / comp / lang / c++-part1 / 8751 < prev    next >
Encoding:
Text File  |  1996-08-05  |  8.7 KB  |  286 lines

  1. Path: news.wwa.com!rmartin
  2. From: rmartin@oma.com (Robert C. Martin)
  3. Newsgroups: comp.object,comp.lang.c++
  4. Subject: Re: A design question
  5. Date: 26 Feb 1996 15:17:22 GMT
  6. Organization: Object Mentor
  7. Message-ID: <RMARTIN.96Feb26091722@rcm.oma.com>
  8. References: <1996Feb22.234825.18755@dcs.warwick.ac.uk>
  9.     <pvcybpuqx6p.fsf@hln56.pki-nbg.philips.de> <312FF1D9.7B02@crl.com>
  10. NNTP-Posting-Host: rcm.oma.com
  11. In-reply-to: Richard Berman's message of Sat, 24 Feb 1996 21:21:29 -0800
  12.  
  13.  
  14.    > miro@dcs.warwick.ac.uk (Miroslav J Walker) writes:
  15.    > 
  16.    >    I'm trying to model input from a user being processed over a
  17.    >    series of steps.  Input is parsed, put into a queue and then
  18.    >    interpreted on a timer. My question is how to model the idea
  19.    >    of it being the same bit of data (essentially) taking on
  20.    >    several forms as it proceeds along the 'pipeline' of
  21.    >    processing.
  22.    > 
  23.  
  24.    Harald Wellmann wrote:
  25.    > 
  26.    > There's a book called "Design Patterns" by Erich Gamma, where the pattern
  27.    > you seem to be thinking of is called a "Chain of Responsibility".
  28.  
  29.  
  30.    Richard Berman <sts@crl.com> writes:
  31.  
  32.    Of course, a state table might do the trick as well.
  33.  
  34.  
  35. Indeed.  And there is a very nice pattern in the "Design Patterns"
  36. book that describes the way in which a state machine can be
  37. implemented to do just what Miroslav is asking.  The pattern is called
  38. "State".  
  39.  
  40. Consider the following:
  41.  
  42. class MyParcel;  /fwd declare.
  43.  
  44. // this class is the abstract representation of the state of the
  45. // parcel of data.  It defines functions which respond to all the
  46. // events that a parcel may experience.
  47.  
  48. class ParcelState
  49. {
  50.   public:
  51.     // the events that occur along the processing chain.
  52.     virtual void Event1(MyParcel&) = 0;
  53.     virtual void Event2(MyParcel&) = 0;
  54. };
  55.  
  56. // This is the parcel itself.  It also defines functions which respond
  57. // to all its events.  However, these functions simply delegate to the
  58. // contained state object.
  59.  
  60. class MyParcel
  61. {
  62.   public:
  63.     MyParcel();
  64.     void Event1() {itsState->Event1(*this);}
  65.     void Event2() {itsState->Event2(*this);}
  66.   private:
  67.     ParcelState* itsState;
  68. };
  69.  
  70.  
  71. We can create derivatives of ParcelState for each state that a
  72. 'MyParcel' object can exist in.  We can then define the implementation
  73. of the Event functions so that in each state the correct operations
  74. take place.
  75.  
  76. Consider the following state table:
  77.  
  78. // Starting State   Event        Ending State    Action
  79. // --------------   -----        ------------    ------
  80.        Raw          Ready        Parsed          Parse
  81.        Raw          Cancel       End             Delete
  82.  
  83.        Parsed       QTime        Enqueued        Enqueue
  84.        Parsed       Cancel       End             Delete
  85.  
  86.        Enqueued     ExecTime     Enqueued        Execute
  87.        Enqueued     Pause        Paused          Dequeue
  88.        Enqueued     Cancel       End             Dequeue,Delete
  89.  
  90.        Paused       Resume       Enqueued        Enqueue
  91.        Paused       Cancel       End             Delete
  92.  
  93. This table describes the behavior of a parcel through a number of
  94. states and events.  The parcel begins in the raw state.  When it is
  95. ready to be parsed, the Parse operation is invoked, and the parcel
  96. goes to the Parsed state.  When it it time to put the parcel on the
  97. queue, then the Enqueue operation is invoked and the parcel goes to
  98. the 'Enqueued' state.  
  99.  
  100. The state machine above handles cancelation of the parcel at any
  101. particular state.  Note that in the 'Enqueued' state the 'Cancel'
  102. event invokes two actions (Dequeue,Delete) whereas in every other
  103. state is simply invokes one action (Delete).
  104.  
  105. To encode this state machine using the 'State' pattern shown above can
  106. be a little tedious.  For that reason I have written a compiler which
  107. takes state tables like the above and translates them into C++ code
  108. that uses the 'State' Pattern.
  109.  
  110. Below is the output generated by the state map compiler for the above
  111. FSM.  If anybody would like a copy of the source code for this
  112. compiler, drop me an email message and I'll mail it to you.
  113.  
  114. ---------------------st.sm (actual input file) -----------------
  115. FSMName Parcel
  116. Context MyParcel
  117. Initial Raw
  118. Header  parcel.h
  119. {
  120.  
  121. // Starting State   Event        Ending State    Action
  122. // --------------   -----        ------------    ------
  123.        Raw          Ready        Parsed          Parse
  124.        Raw          Cancel       End             Delete
  125.  
  126.        Parsed       QTime        Enqueued        Enqueue
  127.        Parsed       Cancel       End             Delete
  128.  
  129.        Enqueued     ExecTime     Enqueued        Execute
  130.        Enqueued     Pause        Paused          Dequeue
  131.        Enqueued     Cancel       End             {Dequeue Delete}
  132.  
  133.        Paused       Resume       Enqueued        Enqueue
  134.        Paused       Cancel       End             Delete
  135.  
  136.        End          *            End             {}
  137.  
  138. }
  139.  
  140. -----------------parcel.h (generated) ----------------------------
  141. #ifndef _H_Parcel
  142. #define _H_Parcel
  143. #include <stddef.h>
  144. #include "parcel.h"
  145. class Parcel;
  146.  
  147. class ParcelState {
  148. public:
  149.  
  150.   virtual const char* StateName() const = 0;
  151.   virtual void Resume(Parcel& s);
  152.   virtual void Pause(Parcel& s);
  153.   virtual void ExecTime(Parcel& s);
  154.   virtual void QTime(Parcel& s);
  155.   virtual void Cancel(Parcel& s);
  156.   virtual void Ready(Parcel& s);
  157. };
  158.  
  159. class ParcelEndState : public ParcelState {
  160. public:
  161.   virtual const char* StateName() const
  162.   {return("End");};
  163. };
  164.  
  165. class ParcelPausedState : public ParcelState {
  166. public:
  167.   virtual const char* StateName() const
  168.   {return("Paused");};
  169.   virtual void Cancel(Parcel&);
  170.   virtual void Resume(Parcel&);
  171. };
  172.  
  173. class ParcelEnqueuedState : public ParcelState {
  174. public:
  175.   virtual const char* StateName() const
  176.   {return("Enqueued");};
  177.   virtual void Cancel(Parcel&);
  178.   virtual void Pause(Parcel&);
  179.   virtual void ExecTime(Parcel&);
  180. };
  181.  
  182. class ParcelParsedState : public ParcelState {
  183. public:
  184.   virtual const char* StateName() const
  185.   {return("Parsed");};
  186.   virtual void Cancel(Parcel&);
  187.   virtual void QTime(Parcel&);
  188. };
  189.  
  190. class ParcelRawState : public ParcelState {
  191. public:
  192.   virtual const char* StateName() const
  193.   {return("Raw");};
  194.   virtual void Cancel(Parcel&);
  195.   virtual void Ready(Parcel&);
  196. };
  197. class Parcel : public MyParcel {
  198.   public:
  199.   static ParcelPausedState PausedState;
  200.   static ParcelEnqueuedState EnqueuedState;
  201.   static ParcelEndState EndState;
  202.   static ParcelParsedState ParsedState;
  203.   static ParcelRawState RawState;
  204.   Parcel();// default constructor
  205.   void Resume() {itsState->Resume(*this);}
  206.   void Pause() {itsState->Pause(*this);}
  207.   void ExecTime() {itsState->ExecTime(*this);}
  208.   void QTime() {itsState->QTime(*this);}
  209.   void Cancel() {itsState->Cancel(*this);}
  210.   void Ready() {itsState->Ready(*this);}
  211.   void SetState(ParcelState& theState) {itsState=&theState;}
  212.   ParcelState& GetState() const {return *itsState;};
  213.   private:
  214.     ParcelState* itsState;
  215. };
  216. #endif
  217.  
  218. ---------------parcel.cc (generated)---------------------
  219. #include "parcel.h"
  220. static char _versID[] = "No Version.";
  221. ParcelPausedState Parcel::PausedState;
  222. ParcelEnqueuedState Parcel::EnqueuedState;
  223. ParcelEndState Parcel::EndState;
  224. ParcelParsedState Parcel::ParsedState;
  225. ParcelRawState Parcel::RawState;
  226. void ParcelState::Resume(Parcel& s)
  227.   {s.FSMError("Resume", s.GetState().StateName());}
  228. void ParcelState::Pause(Parcel& s)
  229.   {s.FSMError("Pause", s.GetState().StateName());}
  230. void ParcelState::ExecTime(Parcel& s)
  231.   {s.FSMError("ExecTime", s.GetState().StateName());}
  232. void ParcelState::QTime(Parcel& s)
  233.   {s.FSMError("QTime", s.GetState().StateName());}
  234. void ParcelState::Cancel(Parcel& s)
  235.   {s.FSMError("Cancel", s.GetState().StateName());}
  236. void ParcelState::Ready(Parcel& s)
  237.   {s.FSMError("Ready", s.GetState().StateName());}
  238. void ParcelPausedState::Cancel(Parcel& s) {
  239.   s.SetState(Parcel::EndState);
  240.   s.Delete();
  241. }
  242. void ParcelPausedState::Resume(Parcel& s) {
  243.   s.SetState(Parcel::EnqueuedState);
  244.   s.Enqueue();
  245. }
  246. void ParcelEnqueuedState::Cancel(Parcel& s) {
  247.   s.SetState(Parcel::EndState);
  248.   s.Dequeue();
  249.   s.Delete();
  250. }
  251. void ParcelEnqueuedState::Pause(Parcel& s) {
  252.   s.SetState(Parcel::PausedState);
  253.   s.Dequeue();
  254. }
  255. void ParcelEnqueuedState::ExecTime(Parcel& s) {
  256.   s.SetState(Parcel::EnqueuedState);
  257.   s.Execute();
  258. }
  259. void ParcelParsedState::Cancel(Parcel& s) {
  260.   s.SetState(Parcel::EndState);
  261.   s.Delete();
  262. }
  263. void ParcelParsedState::QTime(Parcel& s) {
  264.   s.SetState(Parcel::EnqueuedState);
  265.   s.Enqueue();
  266. }
  267. void ParcelRawState::Cancel(Parcel& s) {
  268.   s.SetState(Parcel::EndState);
  269.   s.Delete();
  270. }
  271. void ParcelRawState::Ready(Parcel& s) {
  272.   s.SetState(Parcel::ParsedState);
  273.   s.Parse();
  274. }
  275. Parcel::Parcel() : itsState(&RawState) {}
  276.  
  277.  
  278.  
  279.  
  280. --
  281. Robert Martin       | Design Consulting   | Training courses offered:
  282. Object Mentor Assoc.| rmartin@oma.com     |   OOA/D, C++, Advanced OO
  283. 14619 N. Somerset Cr| Tel: (847) 918-1004 |   Mgt. Overview of OOT
  284. Green Oaks IL 60048 | Fax: (847) 918-1023 | Development Contracts.
  285.  
  286.